import datetime
import multiprocessing

from src.repo import deployment_repo
from src.repo.model.deployment import *
from src.repo.model.enums import DeleteStatus, MergeStatus
from src.service import git_service


def deploy_branch(project_id, environment_id, feature_branch_id):
    deploy = deployment_repo.query_deploy_by_project_env(project_id, environment_id)
    if not deploy:
        # 没有部署过，创建一条记录
        branch_name = git_service.create_deployment_branch(project_id, environment_id)
        print('create deployment branch for [%s, %s]: %s' % (project_id, environment_id, branch_name))
        deploy = Deployment(project_id=project_id, environment_id=environment_id)
        deploy = deployment_repo.create_deployment(deploy)
        # 插入合并分支
        merge_branch = DeploymentMergeBranch(deployment_id=deploy.id_, branch_name=branch_name,
                                             status=DeleteStatus.NOT_DELETED)
        deployment_repo.create_deployment_merge_branch(merge_branch)
        print("创建合并分支成功: %s" % branch_name)
    deployed_branches = deployment_repo.query_deploy_branches(deploy.id_)
    if feature_branch_id:
        # 选择分支进行部署，即添加分支进入部署
        if any(x.branch_id == int(feature_branch_id) for x in deployed_branches):
            raise ValueError("分支已经在部署中")
        feature_branch = deployment_repo.query_branch_by_id(feature_branch_id)
        if not feature_branch:
            raise ValueError(f"分支[{feature_branch_id}]不存在")
        deployment_repo.create_deploy_branch(deploy.id_, feature_branch_id, '')
        deployed_branches = deployment_repo.query_deploy_branches(deploy.id_)
    if len(deployed_branches) == 0:
        raise ValueError("没有部署中的分支")
    adp = deployment_repo.query_active_deployment_process(environment_id)
    if adp:
        raise ValueError("还有正在进行中的部署，请稍后重试")
    dp = deployment_repo.create_deployment_process(DeploymentProcess(environment_id=environment_id,
                                                                     deployment_id=deploy.id_,
                                                                     status=DeploymentProcessStatus.CREATED,
                                                                     process_log=''))
    print(f'插入任务成功: [{dp.id_}]')
    pr = multiprocessing.Process(target=do_deployment_process, args=(dp.id_,))
    pr.start()


def get_deployment_process_by_env(environment_id):
    return deployment_repo.query_active_deployment_process(environment_id)


def do_deployment_process(deployment_process_id):
    datetime_now = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    deployment_process = deployment_repo.query_deployment_process_by_id(deployment_process_id)
    deployment = deployment_repo.query_deployment_by_env(deployment_process.environment_id)
    project = deployment_repo.query_project_by_id(deployment.project_id)
    # 修改状态
    deployment_repo.update_deployment_process(deployment_process_id, DeploymentProcessStatus.RUNNING, None)

    # 开始合并分支
    deployed_branches = deployment_repo.query_deploy_branches(deployment.id_)
    merge_branch = deployment_repo.query_merge_branch_by_deployment_id(deployment.id_)
    # 先把所有分支修改成合并中的状态
    for db in deployed_branches:
        deployment_repo.update_deploy_branch_latest_commit(deployment.id_, db.branch_id, db.latest_commit,
                                                           MergeStatus.WAIT_MERGE)
    # 开始处理merge
    for db in deployed_branches:
        # branch = deployment_repo.query_branch_by_id(db.branch_id)
        # 获取当前分支的commit
        latest_commit = git_service.get_latest_commit(project.local_folder, db.branch_name)
        if latest_commit == db.latest_commit:
            # 未做修改
            print(f'branch [{db.branch_name}] no update. latest commit: [{latest_commit}]')
            continue
        try:
            lc = git_service.do_merge_branch(project.local_folder, merge_branch.branch_name, db.branch_name)
        except OSError as e:
            # 合并冲突
            deployment_repo.update_merge_branch_status(db.deployment_id, MergeStatus.FAIL)
            deployment_repo.update_deploy_branch_latest_commit(deployment.id_, db.branch_id, db.latest_commit,
                                                               MergeStatus.FAIL)
            deployment_repo.update_deployment_process(deployment_process_id, DeploymentProcessStatus.FINISHED,
                                                      datetime_now)
            raise e
        if lc:
            # 合并成功，更新commit
            deployment_repo.update_deploy_branch_latest_commit(deployment.id_, db.branch_id, lc, MergeStatus.SUCCESS)
            print(f'branch [{db.branch_name}] merge success')
        else:
            print(f'ERROR branch [{db.branch_name}] merge failed')
            deployment_repo.update_deploy_branch_latest_commit(deployment.id_, db.branch_id, db['latest_commit'],
                                                               MergeStatus.FAIL)
            deployment_repo.update_merge_branch_status(deployment.id_, MergeStatus.FAIL)
            raise IOError(f"分支[{db.branch_name}]合并失败，请手动合并")

    deployment_repo.update_merge_branch_status(deployment.id_, MergeStatus.SUCCESS)
    deployment_repo.update_deployment_process(deployment_process_id, DeploymentProcessStatus.FINISHED, datetime_now)


def get_latest_commit(branch_id):
    branch = deployment_repo.query_branch_by_id(branch_id)
    project = deployment_repo.query_project_by_id(branch.project_id)
    return git_service.get_latest_commit(project.local_folder, branch.branch_name)


def create_feature_branch(project_id, feature_id):
    branch = deployment_repo.query_branch_project_and_feature(project_id, feature_id)
    if branch:
        raise ValueError("需求下的分支已创建")
    feature = deployment_repo.query_feature_by_id(feature_id)
    if not feature:
        raise ValueError("需求不存在")
    branch_name = git_service.create_feature_branch(project_id, feature_id)
    deployment_repo.create_branch(Branch(project_id=project_id,
                                         feature_id=feature_id,
                                         branch_name=branch_name,
                                         status=BranchStatus.WAIT_INTEGRATE))


def get_environment_info(environment_id):
    """
    获取环境的节本情况，包括分支情况、合并分支
    :param environment_id: 环境ID
    :return:
    """
    env = deployment_repo.query_env_by_id(environment_id)
    deployment = deployment_repo.query_deployment_by_env(environment_id)
    merge_branch = deployment_repo.query_merge_branch_by_deployment_id(deployment.id_)
    return {
        'environment': env,
        'deployment': deployment,
        "merge_branch": merge_branch
    }


def get_deployed_branches(environment_id):
    deployment = deployment_repo.query_deployment_by_env(environment_id)
    bs = deployment_repo.query_deploy_branches(deployment.id_)
    for db in bs:
        db.branch_latest_commit = git_service.get_latest_commit(db.local_folder, db.branch_name)
    return bs


def get_integrated_branches(environment_id):
    return deployment_repo.query_branches(environment_id, BranchStatus.INTEGRATED)


def get_projects():
    return deployment_repo.query_projects()
